﻿// Assignment01.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <GL\glut.h>

#include "mesh.h"

#define SCR_WIDTH 600
#define SCR_HEIGHT 600
#define _USE_MATH_DEFINES
#include <math.h>

using namespace std;

bool bWireFrame; //biến xác định wireFrame hay Color
bool fourView;
bool amination;
int amination01, amination02, amination03;

GLdouble camera_angle; //góc quay so với trục Oy. Độ RAD
GLdouble camera_height; //Chiều cao camera so với Oxz
GLdouble camera_dis; //Khoảng cách đến trục Oy

float plane_posY; //toạ độ Y của sàn nhà trong không gian Oxyz

float nSegnmentsOfCylinder;
float nSlicesStacksOfSphere;

float cylBaseRadius;
float cylBaseHeight;
float cylBaseRotateAngle;

float cuboidBaseSizeXZ;
float cuboidBaseHeight;

float cylAxisRadius;
float cylAxisHeight;
float cylAxisPos;
float cylAxisRotateAngle;

float uShadeSizeX;
float uShadeSizeY;
float uShadeSizeZ;
float uShadeThick;

float cuboidAxisSizeXZ;
float cuboidAxisHeight;
float cuboidAxisPos;
float cuboidAxisRotateAngle;

float cylDiskRadius;
float cylDiskHeight;

float sphere123Radius;
float sphere123Pos;

Mesh planeXZ;
Mesh sphere;
Mesh truncatedCube;
Mesh dodecahedron;
Mesh icosahedron;
Mesh cylBase;
Mesh cuboidBase;
Mesh cylAxis;
Mesh uShade;
Mesh cuboidAxis;
Mesh cylDisk;
Mesh sphere01;
Mesh sphere02;
Mesh sphere03;

//In ra màn hình console các lệnh điều khiển
void printOut(){
	cout << "1, 2: Rotate the base" << endl;
	cout << "3, 4: Rotate axes 1 (cylinder axes)" << endl;
	cout << "5, 6: Rotate axes 2 (cuboid axes)" << endl;
	cout << "W, w: Switch between wireframe and solid mode" << endl;
	cout << "A, a: Turn on/off animation mode" << endl;
	cout << "V, v: to switch between 1 and 4 views" << endl;
	cout << "+   : to increase camera distance." << endl;
	cout << "-   : to decrease camera distance." << endl;
	cout << "up arrow  : to increase camera height." << endl;
	cout << "down arrow: to decrease camera height." << endl;
	cout << "<-        : to rotate camera clockwise." << endl;
	cout << "->        : to rotate camera counterclockwise." << endl;
}

void myObjects();
void myInit();
void myKeyboard(unsigned char key, int x, int y);
void specialInput(int key, int x, int y);
void myDisplay();
void myAmination();

void myDraw();
void drawFloor();
void drawSphere();
void drawTruncatedCube();
void drawDodecahedron();
void drawIcosahedron();
void drawCylBase();
void drawCuboidBase();
void drawCylAxis();
void drawUShade();
void drawCuboidAxis();
void drawCylDisk();
void drawSmallSpheres();

int _tmain(int argc, _TCHAR* argv[])
{
	printOut();

	glutInit(&argc, (char**)argv); //initialize the tool kit
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);//set the display mode
	glutInitWindowSize(SCR_WIDTH, SCR_HEIGHT); //set window size
	glutInitWindowPosition(100, 100); // set window position on screen
	glutCreateWindow("Assignment 1 - Kieu Khuong Thinh (51103398)"); // open the screen window

	myInit();
	myObjects();//Create vertex and face and slideX,Y,Z

	glutKeyboardFunc(myKeyboard);
	glutSpecialFunc(specialInput);
	glutDisplayFunc(myDisplay);
	glutIdleFunc(myAmination);

	glutMainLoop();

	return 0;
}

void myInit(){

	float fHalfSize = 5;

	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glColor3f(0.0f, 0.0f, 0.0f);

	glFrontFace(GL_CW);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);

	bWireFrame = false;
	fourView = false;
	amination = true;

	amination01 = 1;
	amination02 = 1;
	amination03 = 1;

	camera_height = 6.5;
	camera_dis = 8.0;
	camera_angle = 0.0;

	plane_posY = 0;

	nSegnmentsOfCylinder = 25;
	nSlicesStacksOfSphere = 10;

	cylBaseRadius = 1.2;
	cylBaseHeight = 0.2;
	cylBaseRotateAngle = 0.0;

	cuboidBaseSizeXZ = 0.6;
	cuboidBaseHeight = 6.0;

	cylAxisHeight = 0.3;
	cylAxisRadius = 0.1;
	cylAxisPos = 0.2;
	cylAxisRotateAngle = 0.0;

	uShadeSizeX = 1.6;
	uShadeSizeY = 0.3;
	uShadeSizeZ = 1.4;
	uShadeThick = 0.1;

	cuboidAxisHeight = uShadeSizeX - 2 * uShadeThick;
	cuboidAxisSizeXZ = cylAxisRadius / 2.0;
	cuboidAxisPos = cylAxisPos*2.0;
	cuboidAxisRotateAngle = 0.0;

	cylDiskRadius = 0.7;
	cylDiskHeight = 0.1;

	sphere123Radius = cylDiskHeight*1.5;
	sphere123Pos = cylAxisPos / 2.0;
}
void myObjects(){
	planeXZ.CreateXZPlane(10, 10, 1);
	planeXZ.slideY = plane_posY;

	sphere.CreateSphere(nSlicesStacksOfSphere, nSlicesStacksOfSphere, 0.5);
	sphere.slideX = 3;
	sphere.slideY = plane_posY + 0.5;
	sphere.slideZ = -3;

	truncatedCube.CreateTruncatedCube(1);
	truncatedCube.slideX = -3;
	truncatedCube.slideY = plane_posY;
	truncatedCube.slideZ = -3;

	dodecahedron.CreateDodecahedron(1);
	dodecahedron.slideX = -3;
	dodecahedron.slideY = plane_posY;
	dodecahedron.slideZ = 3;

	icosahedron.CreateIcosahedron(1);
	icosahedron.slideX = 3;
	icosahedron.slideY = plane_posY;
	icosahedron.slideZ = 3;

	cylBase.CreateCylinder(nSegnmentsOfCylinder, cylBaseHeight, cylBaseRadius);
	cylBase.slideY = plane_posY;
	cylBase.SetColor(1);

	cuboidBase.CreateCuboid(cuboidBaseSizeXZ, cuboidBaseHeight, cuboidBaseSizeXZ);
	cuboidBase.slideY = plane_posY + cylBaseHeight;
	cuboidBase.SetColor(0);

	cylAxis.CreateCylinder(nSegnmentsOfCylinder, cylAxisHeight, cylAxisRadius);
	cylAxis.slideY = cuboidBase.slideY + cuboidBaseHeight - cylAxisPos;
	cylAxis.slideZ = cuboidBaseSizeXZ / 2.0;
	cylAxis.SetColor(2);

	uShade.CreateUShape(uShadeSizeX, uShadeSizeY, uShadeSizeZ, uShadeThick);
	uShade.slideY = cylAxis.slideY;
	uShade.slideZ = cylAxis.slideZ + cylAxisHeight + uShadeSizeZ/2.0;
	uShade.SetColor(3);

	cuboidAxis.CreateCuboid(cuboidAxisSizeXZ, cuboidAxisHeight, cuboidAxisSizeXZ);
	cuboidAxis.slideY = uShade.slideY;
	cuboidAxis.slideZ = uShadeSizeZ + uShadeSizeZ / 2.0 - cuboidAxisPos;
	cuboidAxis.SetColor(4);

	cylDisk.CreateCylinder(nSegnmentsOfCylinder, cylDiskHeight, cylDiskRadius);
	cylDisk.slideY = cuboidAxis.slideY;
	cylDisk.slideZ = cuboidAxis.slideZ;
	cylDisk.SetColor(5);

	sphere01.CreateSphere(nSlicesStacksOfSphere, nSlicesStacksOfSphere, sphere123Radius);
	sphere01.slideY = cylDisk.slideY;
	sphere01.slideZ = cylDisk.slideZ;
	sphere02.CreateSphere(nSlicesStacksOfSphere, nSlicesStacksOfSphere, sphere123Radius);
	sphere03.CreateSphere(nSlicesStacksOfSphere, nSlicesStacksOfSphere, sphere123Radius);
	sphere01.SetColor(9);
	sphere02.SetColor(10);
	sphere03.SetColor(11);
}
void myKeyboard(unsigned char key, int x, int y){
	switch (key)
	{
	case '1':
		if (!amination) {
			cylBaseRotateAngle += 2;
			if (cylBaseRotateAngle > 360)
				cylBaseRotateAngle -= 360;
		}
		break;
	case '2':
		if (!amination) {
			cylBaseRotateAngle -= 2;
			if (cylBaseRotateAngle < 0)
				cylBaseRotateAngle += 360;
		}
		break;
	case '3':
		if (!amination) {
			cylAxisRotateAngle += 2;
			if (cylAxisRotateAngle > 360)
				cylAxisRotateAngle -= 360;
		}
		break;
	case '4':
		if (!amination) {
			cylAxisRotateAngle -= 2;
			if (cylAxisRotateAngle < 0)
				cylAxisRotateAngle += 360;
		}
		break;
	case '5':
		if (!amination) {
			cuboidAxisRotateAngle += 2;
			if (cylAxisRotateAngle > 360)
				cylAxisRotateAngle -= 360;
		}
		break;
	case '6':
		if (!amination) {
			cuboidAxisRotateAngle -= 2;
			if (cylAxisRotateAngle < 0)
				cylAxisRotateAngle += 360;
		}
		break;
	case 'A':
	case 'a':
		amination = !amination;
		if (amination)
			glutIdleFunc(myAmination);
		else
			glutIdleFunc(NULL);
		break;
	case 'V':
	case 'v':
		fourView = !fourView;
	case '+':
		camera_dis += 0.1;
		break;
	case '-':
		camera_dis -= 0.1;
		break;
	case 'w':
	case 'W':
		bWireFrame = !bWireFrame;
		break;
	}
	glutPostRedisplay();
}

void specialInput(int key, int x, int y){
	switch (key){
	case GLUT_KEY_UP:
		camera_height += 0.1;
		break;
	case GLUT_KEY_DOWN:
		camera_height -= 0.1;
		break;
	case GLUT_KEY_LEFT:
		camera_angle += 2.0*M_PI / 360.0f;
		break;
	case GLUT_KEY_RIGHT:
		camera_angle -= 2.0*M_PI / 360.0f;
		break;
	}
	glutPostRedisplay();
}

void myAmination(){
	cylBaseRotateAngle += amination01*0.02;
	if (amination01*cylBaseRotateAngle > 360)
		amination01 = -amination01;
	
	cylAxisRotateAngle += amination02*0.04;
	if (amination02*cylAxisRotateAngle > 360)
		amination02 = -amination02;

	cuboidAxisRotateAngle += amination03*0.06;
	if (amination03*cylAxisRotateAngle > 360)
		amination03 = -amination03;
	
	glutPostRedisplay();
}

void myDisplay(){

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (fourView) {

		//Left-Top
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(-5, 5, 0, 10, -10, 10);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0.0, 0.0, 5.0, 0, 0, 0, 0, 1, 0);
		glViewport(0, SCR_HEIGHT / 2.0f, SCR_WIDTH / 2.0f, SCR_HEIGHT / 2.0f);
		myDraw();
		
		//Right-Top
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(-5, 5, 0, 10, -10, 10);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(5.0, 0.0, 0.0, 0, 0, 0, 0, 1, 0);
		glViewport(SCR_WIDTH / 2.0f, SCR_HEIGHT / 2.0f, SCR_WIDTH / 2.0f, SCR_HEIGHT / 2.0f);
		myDraw();

		//Left-Bottom
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(-5, 5, -5, 5, -10, 10);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0.0, 5.0, 0.0, 0, 0, 0, 0, 0, 1);
		glViewport(0, 0, SCR_WIDTH / 2.0f, SCR_HEIGHT / 2.0f);
		myDraw();

		//Right-Bottom
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20.0);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(camera_dis*sin(camera_angle),
			camera_height,
			camera_dis*cos(camera_angle), 0, 0, 0, 0, 1, 0);
		glViewport(SCR_WIDTH / 2.0f, 0, SCR_WIDTH / 2.0f, SCR_HEIGHT / 2.0f);
		myDraw();
	}
	else {

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20.0);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(camera_dis*sin(camera_angle),
			camera_height,
			camera_dis*cos(camera_angle), 0, 0, 0, 0, 1, 0);
		glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);

		myDraw();
	}
	glFlush();
	glutSwapBuffers();
}

void myDraw(){
	drawFloor();
	drawSphere();
	drawTruncatedCube();
	drawDodecahedron();
	drawIcosahedron();
	drawCylBase();
	drawCuboidBase();
	drawCylAxis();
	drawUShade();
	drawCuboidAxis();
	drawCylDisk();
	drawSmallSpheres();
}

void drawFloor(){
	glPushMatrix();
	if (bWireFrame)
		planeXZ.DrawWireframe();
	else
		planeXZ.DrawColor();
	glPopMatrix();
}

void drawSphere(){
	glPushMatrix();
	glTranslated(sphere.slideX, sphere.slideY, sphere.slideZ);
	if (bWireFrame)
		sphere.DrawWireframe();
	else
		sphere.DrawColor();
	glPopMatrix();
}

void drawTruncatedCube(){
	glPushMatrix();
	glTranslated(truncatedCube.slideX, truncatedCube.slideY, truncatedCube.slideZ);
	if (bWireFrame)
		truncatedCube.DrawWireframe();
	else
		truncatedCube.DrawColor();
	glPopMatrix();
}

void drawDodecahedron(){
	glPushMatrix();
	glTranslated(dodecahedron.slideX, dodecahedron.slideY + 0.5, dodecahedron.slideZ);
	glScaled(0.309, 0.309, 0.309);
	glTranslated(0.0, 0.0, 0.0);
	if (bWireFrame)
		dodecahedron.DrawWireframe();
	else
		dodecahedron.DrawColor();
	glPopMatrix();
}

void drawIcosahedron(){
	glPushMatrix();
	glTranslated(icosahedron.slideX, icosahedron.slideY + 0.5, icosahedron.slideZ);
	glScaled(0.5, 0.5, 0.5);
	glTranslated(0.0, 0.0, 0.0);
	if (bWireFrame)
		icosahedron.DrawWireframe();
	else
		icosahedron.DrawColor();
	glPopMatrix();
}

void drawCylBase(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(cylBase.slideX, cylBase.slideY, cylBase.slideZ);
	if (bWireFrame)
		cylBase.DrawWireframe();
	else
		cylBase.DrawColor();
	glPopMatrix();
}

void drawCuboidBase(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(cuboidBase.slideX, cuboidBase.slideY, cuboidBase.slideZ);
	if (bWireFrame)
		cuboidBase.DrawWireframe();
	else
		cuboidBase.DrawColor();
	glPopMatrix();
}

void drawCylAxis(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(cylAxis.slideX, cylAxis.slideY, cylAxis.slideZ);
	glRotatef(90, 1, 0, 0);
	glRotated(cylAxisRotateAngle, 0, 1, 0);
	if (bWireFrame)
		cylAxis.DrawWireframe();
	else
		cylAxis.DrawColor();
	glPopMatrix();
}

void drawUShade() {
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(uShade.slideX, uShade.slideY, uShade.slideZ);
	glRotated(cylAxisRotateAngle, 0, 0, 1);
	if (bWireFrame)
		uShade.DrawWireframe();
	else uShade.DrawColor();
	glPopMatrix();
}

void drawCuboidAxis(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(cuboidAxis.slideX, cuboidAxis.slideY, cuboidAxis.slideZ);
	glRotatef(90, 0, 0, 1);
	glRotated(cylAxisRotateAngle, 0, 0, 1);
	glRotated(cuboidAxisRotateAngle, 0, 1, 0);
	glTranslated(0, -cuboidAxisHeight / 2.0, 0);
	if (bWireFrame)
		cuboidAxis.DrawWireframe();
	else
		cuboidAxis.DrawColor();
	glPopMatrix();
}

void drawCylDisk(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	glTranslated(cylDisk.slideX, cylDisk.slideY, cylDisk.slideZ);
	glRotatef(90, 0, 0, 1);
	glRotated(cylAxisRotateAngle, 0, 0, 1);
	glRotated(cuboidAxisRotateAngle, 0, 1, 0);
	glTranslated(0, -cylDiskHeight / 2.0, 0);
	if (bWireFrame)
		cylDisk.DrawWireframe();
	else
		cylDisk.DrawColor();
	glPopMatrix();
}

void drawSmallSpheres(){
	glPushMatrix();
	glRotated(cylBaseRotateAngle, 0, 1, 0);
	////////////////////////////////////
	glTranslated(sphere01.slideX, sphere01.slideY, sphere01.slideZ);
	glRotated(cylAxisRotateAngle, 0, 0, 1);
	glRotated(cuboidAxisRotateAngle, -1, 0, 0);

	/*

	theta = 120;
	x = 0;
	c = cos(theta) = -0.5;
	s = sin(theta) = sqrt(3)/2;

	y = sphereRadius*3;
	z = 0;

	t = y;
	y = c*y - s*z;
	z = s*t + c*z;

	*/

	float x = 0, y = 0, z = 0, t = 0;
	y = cylDiskRadius - sphere123Pos*2.0;

	glTranslatef(0, y, 0);
	if (bWireFrame)
		sphere01.DrawWireframe();
	else
		sphere01.DrawColor();
	////////////////////////////////////
	t = y;
	y = -y + (-0.5 * (cylDiskRadius - sphere123Pos * 2.0));
	z = 0.866*t;
	glTranslatef(0, y, z);
	if (bWireFrame)
		sphere02.DrawWireframe();
	else sphere02.DrawColor();
	///////////////////////////////////
	glTranslatef(0, 0, -2 * z);
	if (bWireFrame)
		sphere03.DrawWireframe();
	else sphere03.DrawColor();

	glPopMatrix();
}